package com.simple.system.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.simple.common.constant.SystemRedisConstans;
import com.simple.common.exception.ServiceException;
import com.simple.framework.core.domain.vo.PagingVo;
import com.simple.framework.core.redis.RedisService;
import com.simple.framework.utils.BeanCopyUtils;
import com.simple.system.domain.dto.AddSysDictionaryDataDto;
import com.simple.system.domain.dto.AddSysDictionaryDto;
import com.simple.system.domain.dto.ListSysDictionaryDto;
import com.simple.system.domain.entity.SysDictionary;
import com.simple.system.domain.entity.SysDictionaryData;
import com.simple.system.mapper.SysDictionaryDataMapper;
import com.simple.system.mapper.SysDictionaryMapper;
import com.simple.system.service.SysDictionaryService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;


/**
 * @Description 字典表(SysDictionary)表服务实现类
 * @Author xiaoke
 * @Date 2024/8/10 18:00
 * @Version 1.0
 */
@Slf4j
@Service("sysDictionaryService")
public class SysDictionaryServiceImpl implements SysDictionaryService {

    private final SysDictionaryMapper sysDictionaryMapper;
    private final SysDictionaryDataMapper sysDictionaryDataMapper;
    private final RedisService redisService;


    public SysDictionaryServiceImpl(SysDictionaryMapper sysDictionaryMapper, SysDictionaryDataMapper sysDictionaryDataMapper, RedisService redisService) {
        this.sysDictionaryMapper = sysDictionaryMapper;
        this.sysDictionaryDataMapper = sysDictionaryDataMapper;
        this.redisService = redisService;
    }

    /**
     * 初始化字典
     */
    @PostConstruct
    public void initSysDictionary() {
        log.info("初始化数据字典到缓存-start");
        List<SysDictionary> sysDictionaries = sysDictionaryMapper.selectList(null);
        for (SysDictionary sysDictionary : sysDictionaries) {
            delectCache(sysDictionary.getCode());
             getDictionaryData(sysDictionary.getCode());
        }
        log.info("初始化数据字典到缓存-end");
    }

    @Override
    public PagingVo<SysDictionary> list(ListSysDictionaryDto dto) {
        dto.setPageNum((dto.getPageNum() - 1) * dto.getPageSize());
        List<SysDictionary> sysListUserVos = sysDictionaryMapper.list(dto);
        return new PagingVo<>(sysListUserVos, sysDictionaryMapper.listTotal(dto));
    }

    @Transactional
    @Override
    public Long crate(AddSysDictionaryDto dto) {
        LambdaQueryWrapper<SysDictionary> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysDictionary::getCode, dto.getCode());
        if (sysDictionaryMapper.selectCount(queryWrapper) > 0) {
            throw new ServiceException("数据字典已存在");
        }
        SysDictionary sysDictionary = BeanCopyUtils.copyBean(dto, SysDictionary.class);
        sysDictionaryMapper.insert(sysDictionary);
        return sysDictionary.getId();
    }

    @Transactional
    @Override
    public void update(Long id, AddSysDictionaryDto dto) {
        SysDictionary sysDictionary = sysDictionaryMapper.selectById(id);
        if (sysDictionary == null) {
            throw new ServiceException("数据字典不存在");
        }
        String oldType = sysDictionary.getCode();
        BeanUtils.copyProperties(dto, sysDictionary);
        LambdaQueryWrapper<SysDictionary> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(SysDictionary::getCode, dto.getCode());
        SysDictionary tempDictionary = sysDictionaryMapper.selectOne(queryWrapper);
        if (tempDictionary != null && !tempDictionary.getId().equals(id)) {
            throw new ServiceException("数据字典已存在");
        }
        sysDictionaryMapper.updateById(sysDictionary);
        //更新字典数据列表类型
        if(!Objects.equals(dto.getCode(), oldType)) {
            updateDictionaryDataType(oldType, sysDictionary.getCode());
        }
        delectCache(sysDictionary.getCode());
    }

    @Transactional
    @Override
    public void delete(Long id) {
        SysDictionary sysDictionary = sysDictionaryMapper.selectById(id);
        if (sysDictionary == null) return;
        if (sysDictionary.getStatus() == 1) {
            throw new ServiceException("数据字典已启用，不能删除");
        }
        String code = sysDictionary.getCode();
        String key = SystemRedisConstans.SYS_DICTIONARY_LIST + code;
        // 删除字典缓存
        if (sysDictionaryMapper.deleteById(id) > 0) {
            redisService.deleteObject(key);
        }
        // 删除字典数据
        LambdaQueryWrapper<SysDictionaryData> queryWrapper = new LambdaQueryWrapper<SysDictionaryData>();
        queryWrapper.eq(SysDictionaryData::getDictType, code);
        sysDictionaryDataMapper.delete(queryWrapper);
    }

    @Override
    public List<SysDictionaryData> getDictionaryData(String type) {
        String key = SystemRedisConstans.SYS_DICTIONARY_LIST + type;
        List<SysDictionaryData> list = redisService.getCacheList(key);
        if (!list.isEmpty()) {
            return list;
        }
        LambdaQueryWrapper<SysDictionaryData> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(SysDictionaryData::getDictType, type)
                .orderByAsc(SysDictionaryData::getDictSort);
        list = sysDictionaryDataMapper.selectList(queryWrapper);
        if(list == null || list.isEmpty()) return list;
        // 缓存数据（2天）
        redisService.setCacheList(key, list, 2, TimeUnit.DAYS);
        return list;
    }

    @Transactional
    @Override
    public Long createData(AddSysDictionaryDataDto dto) {
        LambdaQueryWrapper<SysDictionaryData> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(SysDictionaryData::getDictType, dto.getDictType())
                .eq(SysDictionaryData::getDictValue, dto.getDictValue());
        if (sysDictionaryDataMapper.selectCount(queryWrapper) > 0) {
            throw new ServiceException("数据字典已存在");
        }
        SysDictionaryData sysDictionaryData = BeanCopyUtils.copyBean(dto, SysDictionaryData.class);
        sysDictionaryDataMapper.insert(sysDictionaryData);
        delectCache(dto.getDictType());
        return sysDictionaryData.getId();
    }

    @Transactional
    @Override
    public void updateData(Long id, AddSysDictionaryDataDto dto) {
        SysDictionaryData sysDictionaryData = sysDictionaryDataMapper.selectById(id);
        if (sysDictionaryData == null) {
            throw new ServiceException("数据字典数据不存在");
        }
        BeanUtils.copyProperties(dto, sysDictionaryData);
        LambdaQueryWrapper<SysDictionaryData> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper
                .eq(SysDictionaryData::getDictType, dto.getDictType())
                .eq(SysDictionaryData::getDictValue, dto.getDictValue());
        SysDictionaryData tempDictionaryData = sysDictionaryDataMapper.selectOne(queryWrapper);
        if (tempDictionaryData != null && !tempDictionaryData.getId().equals(id)) {
            throw new ServiceException("数据字典已存在");
        }
        sysDictionaryDataMapper.updateById(sysDictionaryData);
        delectCache(sysDictionaryData.getDictType());
    }

    @Transactional
    @Override
    public void deleteData(Long id) {
        SysDictionaryData sysDictionaryData = sysDictionaryDataMapper.selectById(id);
        if (sysDictionaryData == null) {
            throw new ServiceException("数据字典数据不存在");
        }
        if (sysDictionaryData.getStatus() == 1) {
            throw new ServiceException("数据字典内容已启用，不能删除");
        }
        sysDictionaryDataMapper.deleteById(id);
        delectCache(sysDictionaryData.getDictType());
    }


    /**
     * 删除缓存
     *
     * @param key 数据字典类型
     */
    private void delectCache(String key) {
        redisService.deleteObject(SystemRedisConstans.SYS_DICTIONARY_LIST + key);
    }

    /**
     * 更新数据字典类型
     *
     * @param oldType 数据字典类型
     * @param newType 新数据字典类型
     */
    private void updateDictionaryDataType(String oldType,String newType) {
       sysDictionaryDataMapper.updateDictType(oldType,newType);
    }
}

